import type { Types } from '@cornerstonejs/core';

export type AnnotationMetadata = Types.ViewReference & {
  /**
   * The registered name of the tool
   */
  toolName: string;
  /**
   * The position of the camera in world space.
   */
  cameraPosition?: Types.Point3;
  /**
   * The viewUp for the view position
   */
  viewUp?: Types.Point3;

  /** The color of the segmentation - really this is annotation data */
  segmentColor?;

  /** The enable element of the annotation */
  enabledElement?: Types.IEnabledElement;
};

export type AnnotationData = {
  /**
   * Annotation handles that are grabbable for manipulation
   */
  handles?: Handles;
  /**
   * Cached Annotation statistics which is specific to the tool
   */
  cachedStats?: Record<string, unknown>;
  /**
   * Label of an annotation
   */
  label?: string;
  /**
   * contour data
   */
  contour?: Contour;

  /**
   * Other data/keys
   */
  [key: string]: unknown;
};

/**
 * Defines the basic annotation type.  This SHOULD be an interface, but
 * typescript doesn't properly handle extending interfaces.
 */
export type Annotation = {
  /** A unique identifier for this annotation */
  annotationUID?: string;
  /**
   * Parent annotation UID
   *
   * An annotation may have a parent annotation when it is, for example, a
   * hole inside a contour.
   */
  parentAnnotationUID?: string;
  /**
   * The interpolationUID, to match up annotations getting interpolated
   */
  interpolationUID?: string;
  /**
   * Array that contains all child annotation UID
   *
   * An annotation may have one or more child annotations when it is contour
   * and have some holes in it.
   */
  childAnnotationUIDs?: string[];
  /** If the annotation is being hovered over and is highlighted */
  highlighted?: boolean;
  /** If the annotation is locked for manipulation */
  isLocked?: boolean;
  /** If the annotation is visible for manipulation */
  isVisible?: boolean;
  /** Has annotation data been invalidated (e.g., as a result of mouse interactions) */
  invalidated?: boolean;
  /** If the annotation is selected */
  isSelected?: boolean;
  /** If the annotation is auto generated from other annotations*/
  autoGenerated?: boolean;
  /** Metadata for annotation.  Optional for any type, but required for measurements */
  metadata?: AnnotationMetadata;
  /**
   * Data for annotation, Derivatives need to define their own data types.
   */
  data: AnnotationData;
  /**
   * The predecessorImageId is the image id this instance object was loaded
   * from.  It is the predecessor since the current annotation state may not
   * reflect the current state and this object is in fact not the loaded object.
   *
   * This can be set to distinguish annotation sources externally to CS3D.
   */
  predecessorImageId?: string;
};

export type Contour = {
  /** world location of the polyline in the space */
  polyline?: Types.Point3[];
  /** PointsManager */
  pointsManager?: Types.IPointsManager<Types.Point3>;
  /** boolean indicating if the contour is closed */
  closed?: boolean;
};

/** Array of annotations */
export type Annotations = Array<Annotation>;

export type GroupSpecificAnnotations = {
  /** Each tool annotations */
  [toolName: string]: Annotations;
};

/**
 * All frame of reference specific annotations for all tools.
 */
export type AnnotationState = {
  /**
   * A string representing the key that can be used
   * to retrieve the key-specific annotations. For instance, our default
   * annotation state key is the FrameOfReferenceUID which is for our default
   * frameOfReferenceAnnotationManager. You can write your own annotation manager
   * that works for a different use case and use a different key.
   */
  [key: string]: GroupSpecificAnnotations;
};

export type Handles = {
  /** world location of the handles in the space */
  points?: Types.Point3[];
  /** index of the active handle being manipulated */
  activeHandleIndex?: number | null;
  /** annotation text box information */
  textBox?: {
    /** whether the text box has moved */
    hasMoved?: boolean;
    /** the world location of the text box */
    worldPosition?: Types.Point3;
    /** text box bounding box information */
    worldBoundingBox?: {
      /** Top left location of the text box in the world space */
      topLeft: Types.Point3;
      /** Top right location of the text box in the world space */
      topRight: Types.Point3;
      /** Bottom left location of the text box in the world space */
      bottomLeft: Types.Point3;
      /** Bottom right location of the text box in the world space */
      bottomRight: Types.Point3;
    };
  };
  [key: string]: unknown;
};
